From 1bb7e0437bb0b3cda7eb47caaac9516d5bb1970a Mon Sep 17 00:00:00 2001 From: Keir Fraser Date: Thu, 5 Feb 2009 12:16:28 +0000 Subject: [PATCH] Add a new domctl to get a single record from the HVM save context Signed-off-by: Tim Deegan --- xen/arch/x86/domctl.c | 28 ++++++++++++++++++++++ xen/common/hvm/save.c | 48 +++++++++++++++++++++++++++++++++++++ xen/include/public/domctl.h | 12 ++++++++++ xen/include/xen/hvm/save.h | 2 ++ xen/xsm/flask/hooks.c | 1 + 5 files changed, 91 insertions(+) diff --git a/xen/arch/x86/domctl.c b/xen/arch/x86/domctl.c index 444370ed89..ab28b22725 100644 --- a/xen/arch/x86/domctl.c +++ b/xen/arch/x86/domctl.c @@ -417,6 +417,34 @@ long arch_do_domctl( } break; + case XEN_DOMCTL_gethvmcontext_partial: + { + struct domain *d; + + ret = -ESRCH; + if ( (d = rcu_lock_domain_by_id(domctl->domain)) == NULL ) + break; + + ret = xsm_hvmcontext(d, domctl->cmd); + if ( ret ) + goto gethvmcontext_partial_out; + + ret = -EINVAL; + if ( !is_hvm_domain(d) ) + goto gethvmcontext_partial_out; + + domain_pause(d); + ret = hvm_save_one(d, domctl->u.hvmcontext_partial.type, + domctl->u.hvmcontext_partial.instance, + domctl->u.hvmcontext_partial.buffer); + domain_unpause(d); + + gethvmcontext_partial_out: + rcu_unlock_domain(d); + } + break; + + case XEN_DOMCTL_set_address_size: { struct domain *d; diff --git a/xen/common/hvm/save.c b/xen/common/hvm/save.c index cb3cf66885..66876e6a1c 100644 --- a/xen/common/hvm/save.c +++ b/xen/common/hvm/save.c @@ -26,6 +26,7 @@ #include #include #include +#include #include @@ -75,6 +76,53 @@ size_t hvm_save_size(struct domain *d) return sz; } +/* Extract a single instance of a save record, by marshalling all + * records of that type and copying out the one we need. */ +int hvm_save_one(struct domain *d, uint16_t typecode, uint16_t instance, + XEN_GUEST_HANDLE_64(uint8) handle) +{ + int rv = 0; + size_t sz = 0; + struct vcpu *v; + hvm_domain_context_t ctxt = { 0, }; + + if ( d->is_dying + || typecode > HVM_SAVE_CODE_MAX + || hvm_sr_handlers[typecode].size < sizeof(struct hvm_save_descriptor) + || hvm_sr_handlers[typecode].save == NULL ) + return -EINVAL; + + if ( hvm_sr_handlers[typecode].kind == HVMSR_PER_VCPU ) + for_each_vcpu(d, v) + sz += hvm_sr_handlers[typecode].size; + else + sz = hvm_sr_handlers[typecode].size; + + if ( (instance + 1) * hvm_sr_handlers[typecode].size > sz ) + return -EINVAL; + + ctxt.size = sz; + ctxt.data = xmalloc_bytes(sz); + if ( !ctxt.data ) + return -ENOMEM; + + if ( hvm_sr_handlers[typecode].save(d, &ctxt) != 0 ) + { + gdprintk(XENLOG_ERR, + "HVM save: failed to save type %"PRIu16"\n", typecode); + rv = -EFAULT; + } + else if ( copy_to_guest(handle, + ctxt.data + + (instance * hvm_sr_handlers[typecode].size) + + sizeof (struct hvm_save_descriptor), + hvm_sr_handlers[typecode].size + - sizeof (struct hvm_save_descriptor)) ) + rv = -EFAULT; + + xfree(ctxt.data); + return rv; +} int hvm_save(struct domain *d, hvm_domain_context_t *h) { diff --git a/xen/include/public/domctl.h b/xen/include/public/domctl.h index 70cede1176..042ccf185c 100644 --- a/xen/include/public/domctl.h +++ b/xen/include/public/domctl.h @@ -630,6 +630,17 @@ struct xen_domctl_debug_op { typedef struct xen_domctl_debug_op xen_domctl_debug_op_t; DEFINE_XEN_GUEST_HANDLE(xen_domctl_debug_op_t); +/* + * Request a particular record from the HVM context + */ +#define XEN_DOMCTL_gethvmcontext_partial 55 +typedef struct xen_domctl_hvmcontext_partial { + uint32_t type; /* IN: Type of record required */ + uint32_t instance; /* IN: Instance of that type */ + XEN_GUEST_HANDLE_64(uint8) buffer; /* OUT: buffer to write record into */ +} xen_domctl_hvmcontext_partial_t; +DEFINE_XEN_GUEST_HANDLE(xen_domctl_hvmcontext_partial_t); + struct xen_domctl { uint32_t cmd; @@ -658,6 +669,7 @@ struct xen_domctl { struct xen_domctl_settimeoffset settimeoffset; struct xen_domctl_real_mode_area real_mode_area; struct xen_domctl_hvmcontext hvmcontext; + struct xen_domctl_hvmcontext_partial hvmcontext_partial; struct xen_domctl_address_size address_size; struct xen_domctl_sendtrigger sendtrigger; struct xen_domctl_get_device_group get_device_group; diff --git a/xen/include/xen/hvm/save.h b/xen/include/xen/hvm/save.h index 723369e248..49e9113493 100644 --- a/xen/include/xen/hvm/save.h +++ b/xen/include/xen/hvm/save.h @@ -152,6 +152,8 @@ __initcall(__hvm_register_##_x##_save_and_restore); /* Entry points for saving and restoring HVM domain state */ size_t hvm_save_size(struct domain *d); int hvm_save(struct domain *d, hvm_domain_context_t *h); +int hvm_save_one(struct domain *d, uint16_t typecode, uint16_t instance, + XEN_GUEST_HANDLE_64(uint8) handle); int hvm_load(struct domain *d, hvm_domain_context_t *h); /* Arch-specific definitions. */ diff --git a/xen/xsm/flask/hooks.c b/xen/xsm/flask/hooks.c index 0499d79bc4..2b996c5d1e 100644 --- a/xen/xsm/flask/hooks.c +++ b/xen/xsm/flask/hooks.c @@ -820,6 +820,7 @@ static int flask_hvmcontext(struct domain *d, uint32_t cmd) perm = HVM__SETHVMC; break; case XEN_DOMCTL_gethvmcontext: + case XEN_DOMCTL_gethvmcontext_partial: perm = HVM__GETHVMC; break; default: -- 2.30.2